package com.shadow.study.ip.client.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shadow.study.ip.client.utils.HttpUtils;
import com.shadow.study.ip.client.utils.ResultInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.Objects;

@Slf4j
@Service
@EnableScheduling
public class IPInfoService {

    private static final String PUBLIC_IP_URL = "https://icanhazip.com/";
    private static final String PRE_PUBLIC = "public_";
    private static final String PRE_LOCAL = "local_";

    private final Environment environment;
    private final IpInfoMapper ipInfoMapper;

    IPInfoService(Environment environment, IpInfoMapper ipInfoMapper) {
        this.environment = environment;
        this.ipInfoMapper = ipInfoMapper;
    }

    /**
     * 获取公网ip
     */
    @Scheduled(cron = "${ip.public.cron}")
    public void getPublicIp() {
        if (!StringUtils.equals(environment.getProperty("ip.public.enable"), Boolean.TRUE.toString())) {
            return;
        }
        ResultInfo resultInfo = HttpUtils.sendGet(PUBLIC_IP_URL, null);
        if (resultInfo.isResult()) {
            String ip = (resultInfo.getData() + StringUtils.EMPTY).replace("\n", StringUtils.EMPTY);
            String localHostName = getLocalHostName();
            String type = PRE_PUBLIC + localHostName;
            execute(type, localHostName, ip);
        }
    }

    /**
     * 获取本地ip
     */
    @Scheduled(cron = "${ip.local.cron}")
    public void getLocalIp() {
        if (!StringUtils.equals(environment.getProperty("ip.local.enable"), Boolean.TRUE.toString())) {
            return;
        }
        String ip = getAppAddressInfo();
        String localHostName = getLocalHostName();
        String type = PRE_LOCAL + localHostName;
        execute(type, localHostName, ip);
    }

    /**
     * 执行
     * */
    public void execute(final String type, final String localHostName, final String ip) {
        log.info("execute type : {}", type);
        IpInfoEntity latestData = getLatestData(type, ip);
        if (Objects.isNull(latestData)) {
            IpInfoEntity ipInfoEntity = new IpInfoEntity()
                    .setType(type)
                    .setMachineName(localHostName)
                    .setIpAddress(ip)
                    .setAddDate(Calendar.getInstance().getTime())
                    .setSum(1);
            log.info("Insert IP : {}", ipInfoEntity.getIpAddress());
            ipInfoMapper.insert(ipInfoEntity);
            return;
        }
        latestData.setSum(latestData.getSum() + 1);
        ipInfoMapper.updateById(latestData);
        log.info("Update IP : {}", latestData.getIpAddress());
    }

    /**
     * 获取最新的IP信息
     * */
    public IpInfoEntity getLatestData(final String type, final String ip) {
        LambdaQueryWrapper<IpInfoEntity> wrapper = new LambdaQueryWrapper<IpInfoEntity>()
                .eq(IpInfoEntity::getType, type)
                .eq(IpInfoEntity::getIpAddress, ip)
                .orderByDesc(IpInfoEntity::getAddDate)
                .last("limit 1");
        return ipInfoMapper.selectOne(wrapper);
    }

    /**
     * 获取本机机器名
     * */
    public static String getLocalHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            log.error("获取本机机器名异常", e);
        }
        return null;
    }

    /**
     * 获取本地ip
     * */
    public static String getAppAddressInfo() {
        StringBuilder ipAddress = new StringBuilder();
        Boolean isFirst = Boolean.TRUE;
        try {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
                while (inetAddresses.hasMoreElements()) {
                    InetAddress inetAddress = inetAddresses.nextElement();
                    if (!inetAddress.isLoopbackAddress() &&
                            !inetAddress.isLinkLocalAddress()
                            && inetAddress.isSiteLocalAddress()
                    ) {
                        String hostAddress = inetAddress.getHostAddress();
                        if (Boolean.FALSE.equals(isFirst)) {
                            ipAddress.append(",");
                        }
                        ipAddress.append(hostAddress);
                        isFirst = Boolean.FALSE;
                    }
                }
            }
        } catch (SocketException e) {
            log.error("获取ip异常", e);
        }
        return ipAddress.toString();
    }
}
